from sqlalchemy import Table, Integer, Unicode, Column, ForeignKey, select, and_, func
from sqlalchemy.orm import mapper, object_mapper, object_session, relation, synonym, column_property

from brainfreeze import OneToOneMapperExtension

from tortuga.database import metadata
from tortuga.models.util import Base, KeymasterCollection
from tortuga.models.revision import Revision, revision_table
from tortuga.models.template import Template
from tortuga.models.gadget import Container

__all__ = ['Page', 'page_table', 'page_localized_table', 'page_generic_table']

page_generic_table = Table('page_generic', metadata,
    Column('generic_id', Integer, primary_key=True),
    Column('path_name', Unicode(200), nullable=False),
    Column('parent_id', None, ForeignKey('content.content_id'), nullable=True),
    Column('template_id', None, ForeignKey('content.content_id'), nullable=True)
)
page_localized_table = Table('page_localized', metadata,
    Column('localized_id', Integer, primary_key=True),
    Column('title', Unicode(200), nullable=False),
)
page_table = Table('page', metadata,
    Column('revision_id', None, ForeignKey('revision.revision_id'), primary_key=True),
    Column('content_id', None, ForeignKey('content.content_id')),
    Column('page_generic_id', None, ForeignKey('page_generic.generic_id')),
    Column('page_localized_id', None, ForeignKey('page_localized.localized_id'))
)

class Page(Revision):
    """Represents an actual web page"""
    class Localized(Base):
        pass
    class Generic(Base):
        pass

    def new_revision(self, _readonly_properties=None, 
        _revisioned_onetoone_relations=None, **kwargs):
        """Return a new revision of this Page instance."""
        # Determine which properties *not* to copy over to a new instance
        readonly_properties = []
        if _readonly_properties: 
            readonly_properties.extend(_readonly_properties)
        # Specify which one_to_one relations should be revisioned
        revisioned_onetoone_relations = ['_page_localized', '_page_generic']
        if _revisioned_onetoone_relations:
            revisioned_onetoone_relations.extend(_revisioned_onetoone_relations)
        return super(Page, self).new_revision(
            readonly_properties, revisioned_onetoone_relations, **kwargs
        )

mapper(Page.Generic, page_generic_table,
    properties={
        'template': relation(Template, uselist=False,
            primaryjoin=and_( # By default get the LATEST revision of this template
                page_generic_table.c.template_id==Template.content_id,
                Template.revision_id==select(
                    [func.max(revision_table.c.revision_id)],
                    group_by=revision_table.c.content_id,
                    having=revision_table.c.content_id==Template.content_id
                ).label('latest_revision')
            ),
            foreign_keys=[page_generic_table.c.template_id]
        )
    }
)
mapper(Page.Localized, page_localized_table)
m = mapper(Page, page_table, inherits=Revision, polymorphic_identity=u'page',
    extension=[OneToOneMapperExtension(Page.Generic, Page.Localized)],
)
# 'containers' relation must be added after Page has been mapped, so that we
# can refer to Page.content_id in the primaryjoin condition
m.add_property('containers',
    relation(Container, cascade="all, delete, delete-orphan",
        primaryjoin=Container.parent_content_id==Page.content_id,
        foreign_keys=[Container.parent_content_id],
        collection_class=lambda: 
            KeymasterCollection(lambda name: Container(container_name=name), 'container_name')
    )
)